home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / perl5 / 5.8.7 / Math / BigRat.pm < prev    next >
Text File  |  2006-04-25  |  45KB  |  1,689 lines

  1.  
  2. #
  3. # "Tax the rat farms." - Lord Vetinari
  4. #
  5.  
  6. # The following hash values are used:
  7. #   sign : +,-,NaN,+inf,-inf
  8. #   _d   : denominator
  9. #   _n   : numeraotr (value = _n/_d)
  10. #   _a   : accuracy
  11. #   _p   : precision
  12. # You should not look at the innards of a BigRat - use the methods for this.
  13.  
  14. package Math::BigRat;
  15.  
  16. require 5.005_03;
  17. use strict;
  18.  
  19. use Math::BigFloat;
  20. use vars qw($VERSION @ISA $upgrade $downgrade
  21.             $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
  22.  
  23. @ISA = qw(Math::BigFloat);
  24.  
  25. $VERSION = '0.15';
  26.  
  27. use overload;            # inherit overload from Math::BigFloat
  28.  
  29. BEGIN
  30.   { 
  31.   *objectify = \&Math::BigInt::objectify;     # inherit this from BigInt
  32.   *AUTOLOAD = \&Math::BigFloat::AUTOLOAD;    # can't inherit AUTOLOAD
  33.   # we inherit these from BigFloat because currently it is not possible
  34.   # that MBF has a different $MBI variable than we, because MBF also uses
  35.   # Math::BigInt::config->('lib'); (there is always only one library loaded)
  36.   *_e_add = \&Math::BigFloat::_e_add;
  37.   *_e_sub = \&Math::BigFloat::_e_sub;
  38.   *as_int = \&as_number;
  39.   *is_pos = \&is_positive;
  40.   *is_neg = \&is_negative;
  41.   }
  42.  
  43. ##############################################################################
  44. # Global constants and flags. Access these only via the accessor methods!
  45.  
  46. $accuracy = $precision = undef;
  47. $round_mode = 'even';
  48. $div_scale = 40;
  49. $upgrade = undef;
  50. $downgrade = undef;
  51.  
  52. # These are internally, and not to be used from the outside at all!
  53.  
  54. $_trap_nan = 0;                         # are NaNs ok? set w/ config()
  55. $_trap_inf = 0;                         # are infs ok? set w/ config()
  56.  
  57. # the package we are using for our private parts, defaults to:
  58. # Math::BigInt->config()->{lib}
  59. my $MBI = 'Math::BigInt::Calc';
  60.  
  61. my $nan = 'NaN';
  62. my $class = 'Math::BigRat';
  63.  
  64. sub isa
  65.   {
  66.   return 0 if $_[1] =~ /^Math::Big(Int|Float)/;        # we aren't
  67.   UNIVERSAL::isa(@_);
  68.   }
  69.  
  70. ##############################################################################
  71.  
  72. sub _new_from_float
  73.   {
  74.   # turn a single float input into a rational number (like '0.1')
  75.   my ($self,$f) = @_;
  76.  
  77.   return $self->bnan() if $f->is_nan();
  78.   return $self->binf($f->{sign}) if $f->{sign} =~ /^[+-]inf$/;
  79.  
  80.   $self->{_n} = $MBI->_copy( $f->{_m} );    # mantissa
  81.   $self->{_d} = $MBI->_one();
  82.   $self->{sign} = $f->{sign} || '+';
  83.   if ($f->{_es} eq '-')
  84.     {
  85.     # something like Math::BigRat->new('0.1');
  86.     # 1 / 1 => 1/10
  87.     $MBI->_lsft ( $self->{_d}, $f->{_e} ,10);    
  88.     }
  89.   else
  90.     {
  91.     # something like Math::BigRat->new('10');
  92.     # 1 / 1 => 10/1
  93.     $MBI->_lsft ( $self->{_n}, $f->{_e} ,10) unless 
  94.       $MBI->_is_zero($f->{_e});    
  95.     }
  96.   $self;
  97.   }
  98.  
  99. sub new
  100.   {
  101.   # create a Math::BigRat
  102.   my $class = shift;
  103.  
  104.   my ($n,$d) = @_;
  105.  
  106.   my $self = { }; bless $self,$class;
  107.  
  108.   # input like (BigInt) or (BigFloat):
  109.   if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
  110.     {
  111.     if ($n->isa('Math::BigFloat'))
  112.       {
  113.       $self->_new_from_float($n);
  114.       }
  115.     if ($n->isa('Math::BigInt'))
  116.       {
  117.       # TODO: trap NaN, inf
  118.       $self->{_n} = $MBI->_copy($n->{value});        # "mantissa" = N
  119.       $self->{_d} = $MBI->_one();            # d => 1
  120.       $self->{sign} = $n->{sign};
  121.       }
  122.     if ($n->isa('Math::BigInt::Lite'))
  123.       {
  124.       # TODO: trap NaN, inf
  125.       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
  126.       $self->{_n} = $MBI->_new(abs($$n));        # "mantissa" = N
  127.       $self->{_d} = $MBI->_one();            # d => 1
  128.       }
  129.     return $self->bnorm();                # normalize (120/1 => 12/10)
  130.     }
  131.  
  132.   # input like (BigInt,BigInt) or (BigLite,BigLite):
  133.   if (ref($d) && ref($n))
  134.     {
  135.     # do N first (for $self->{sign}):
  136.     if ($n->isa('Math::BigInt'))
  137.       {
  138.       # TODO: trap NaN, inf
  139.       $self->{_n} = $MBI->_copy($n->{value});        # "mantissa" = N
  140.       $self->{sign} = $n->{sign};
  141.       }
  142.     elsif ($n->isa('Math::BigInt::Lite'))
  143.       {
  144.       # TODO: trap NaN, inf
  145.       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
  146.       $self->{_n} = $MBI->_new(abs($$n));        # "mantissa" = $n
  147.       }
  148.     else
  149.       {
  150.       require Carp;
  151.       Carp::croak(ref($n) . " is not a recognized object format for Math::BigRat->new");
  152.       }
  153.     # now D:
  154.     if ($d->isa('Math::BigInt'))
  155.       {
  156.       # TODO: trap NaN, inf
  157.       $self->{_d} = $MBI->_copy($d->{value});        # "mantissa" = D
  158.       # +/+ or -/- => +, +/- or -/+ => -
  159.       $self->{sign} = $d->{sign} ne $self->{sign} ? '-' : '+';
  160.       }
  161.     elsif ($d->isa('Math::BigInt::Lite'))
  162.       {
  163.       # TODO: trap NaN, inf
  164.       $self->{_d} = $MBI->_new(abs($$d));        # "mantissa" = D
  165.       my $ds = '+'; $ds = '-' if $$d < 0;
  166.       # +/+ or -/- => +, +/- or -/+ => -
  167.       $self->{sign} = $ds ne $self->{sign} ? '-' : '+';
  168.       }
  169.     else
  170.       {
  171.       require Carp;
  172.       Carp::croak(ref($d) . " is not a recognized object format for Math::BigRat->new");
  173.       }
  174.     return $self->bnorm();                # normalize (120/1 => 12/10)
  175.     }
  176.   return $n->copy() if ref $n;                # already a BigRat
  177.  
  178.   if (!defined $n)
  179.     {
  180.     $self->{_n} = $MBI->_zero();            # undef => 0
  181.     $self->{_d} = $MBI->_one();
  182.     $self->{sign} = '+';
  183.     return $self;
  184.     }
  185.  
  186.   # string input with / delimiter
  187.   if ($n =~ /\s*\/\s*/)
  188.     {
  189.     return $class->bnan() if $n =~ /\/.*\//;    # 1/2/3 isn't valid
  190.     return $class->bnan() if $n =~ /\/\s*$/;    # 1/ isn't valid
  191.     ($n,$d) = split (/\//,$n);
  192.     # try as BigFloats first
  193.     if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
  194.       {
  195.       local $Math::BigFloat::accuracy = undef;
  196.       local $Math::BigFloat::precision = undef;
  197.  
  198.       # one of them looks like a float 
  199.       my $nf = Math::BigFloat->new($n,undef,undef);
  200.       $self->{sign} = '+';
  201.       return $self->bnan() if $nf->is_nan();
  202.  
  203.       $self->{_n} = $MBI->_copy( $nf->{_m} );    # get mantissa
  204.  
  205.       # now correct $self->{_n} due to $n
  206.       my $f = Math::BigFloat->new($d,undef,undef);
  207.       return $self->bnan() if $f->is_nan();
  208.       $self->{_d} = $MBI->_copy( $f->{_m} );
  209.  
  210.       # calculate the difference between nE and dE
  211.       # XXX TODO: check that exponent() makes a copy to avoid copy()
  212.       my $diff_e = $nf->exponent()->copy()->bsub( $f->exponent);
  213.       if ($diff_e->is_negative())
  214.     {
  215.         # < 0: mul d with it
  216.         $MBI->_lsft( $self->{_d}, $MBI->_new( $diff_e->babs()), 10);
  217.     }
  218.       elsif (!$diff_e->is_zero())
  219.         {
  220.         # > 0: mul n with it
  221.         $MBI->_lsft( $self->{_n}, $MBI->_new( $diff_e), 10);
  222.         }
  223.       }
  224.     else
  225.       {
  226.       # both d and n look like (big)ints
  227.  
  228.       $self->{sign} = '+';                    # no sign => '+'
  229.       $self->{_n} = undef;
  230.       $self->{_d} = undef;
  231.       if ($n =~ /^([+-]?)0*(\d+)\z/)                # first part ok?
  232.     {
  233.     $self->{sign} = $1 || '+';                # no sign => '+'
  234.     $self->{_n} = $MBI->_new($2 || 0);
  235.         }
  236.  
  237.       if ($d =~ /^([+-]?)0*(\d+)\z/)                # second part ok?
  238.     {
  239.     $self->{sign} =~ tr/+-/-+/ if ($1 || '') eq '-';    # negate if second part neg.
  240.     $self->{_d} = $MBI->_new($2 || 0);
  241.         }
  242.  
  243.       if (!defined $self->{_n} || !defined $self->{_d})
  244.     {
  245.         $d = Math::BigInt->new($d,undef,undef) unless ref $d;
  246.         $n = Math::BigInt->new($n,undef,undef) unless ref $n;
  247.  
  248.         if ($n->{sign} =~ /^[+-]$/ && $d->{sign} =~ /^[+-]$/)
  249.       { 
  250.       # both parts are ok as integers (wierd things like ' 1e0'
  251.           $self->{_n} = $MBI->_copy($n->{value});
  252.           $self->{_d} = $MBI->_copy($d->{value});
  253.           $self->{sign} = $n->{sign};
  254.           $self->{sign} =~ tr/+-/-+/ if $d->{sign} eq '-';    # -1/-2 => 1/2
  255.           return $self->bnorm();
  256.       }
  257.  
  258.         $self->{sign} = '+';                    # a default sign
  259.         return $self->bnan() if $n->is_nan() || $d->is_nan();
  260.  
  261.     # handle inf cases:
  262.         if ($n->is_inf() || $d->is_inf())
  263.       {
  264.       if ($n->is_inf())
  265.         {
  266.         return $self->bnan() if $d->is_inf();        # both are inf => NaN
  267.         my $s = '+';         # '+inf/+123' or '-inf/-123'
  268.         $s = '-' if substr($n->{sign},0,1) ne $d->{sign};
  269.         # +-inf/123 => +-inf
  270.         return $self->binf($s);
  271.         }
  272.           # 123/inf => 0
  273.           return $self->bzero();
  274.       }
  275.     }
  276.       }
  277.  
  278.     return $self->bnorm();
  279.     }
  280.  
  281.   # simple string input
  282.   if (($n =~ /[\.eE]/))
  283.     {
  284.     # looks like a float, quacks like a float, so probably is a float
  285.     $self->{sign} = 'NaN';
  286.     local $Math::BigFloat::accuracy = undef;
  287.     local $Math::BigFloat::precision = undef;
  288.     $self->_new_from_float(Math::BigFloat->new($n,undef,undef));
  289.     }
  290.   else
  291.     {
  292.     # for simple forms, use $MBI directly
  293.     if ($n =~ /^([+-]?)0*(\d+)\z/)
  294.       {
  295.       $self->{sign} = $1 || '+';
  296.       $self->{_n} = $MBI->_new($2 || 0);
  297.       $self->{_d} = $MBI->_one();
  298.       }
  299.     else
  300.       {
  301.       my $n = Math::BigInt->new($n,undef,undef);
  302.       $self->{_n} = $MBI->_copy($n->{value});
  303.       $self->{_d} = $MBI->_one();
  304.       $self->{sign} = $n->{sign};
  305.       return $self->bnan() if $self->{sign} eq 'NaN';
  306.       return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/;
  307.       }
  308.     }
  309.   $self->bnorm();
  310.   }
  311.  
  312. sub copy
  313.   {
  314.   # if two arguments, the first one is the class to "swallow" subclasses
  315.   my ($c,$x) = @_;
  316.  
  317.   if (scalar @_ == 1)
  318.     {
  319.     $x = $_[0];
  320.     $c = ref($x);
  321.     }
  322.   return unless ref($x); # only for objects
  323.  
  324.   my $self = bless {}, $c;
  325.  
  326.   $self->{sign} = $x->{sign};
  327.   $self->{_d} = $MBI->_copy($x->{_d});
  328.   $self->{_n} = $MBI->_copy($x->{_n});
  329.   $self->{_a} = $x->{_a} if defined $x->{_a};
  330.   $self->{_p} = $x->{_p} if defined $x->{_p};
  331.   $self;
  332.   }
  333.  
  334. ##############################################################################
  335.  
  336. sub config
  337.   {
  338.   # return (later set?) configuration data as hash ref
  339.   my $class = shift || 'Math::BigRat';
  340.  
  341.   my $cfg = $class->SUPER::config(@_);
  342.  
  343.   # now we need only to override the ones that are different from our parent
  344.   $cfg->{class} = $class;
  345.   $cfg->{with} = $MBI;
  346.   $cfg;
  347.   }
  348.  
  349. ##############################################################################
  350.  
  351. sub bstr
  352.   {
  353.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  354.  
  355.   if ($x->{sign} !~ /^[+-]$/)        # inf, NaN etc
  356.     {
  357.     my $s = $x->{sign}; $s =~ s/^\+//;     # +inf => inf
  358.     return $s;
  359.     }
  360.  
  361.   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';    # '+3/2' => '3/2'
  362.  
  363.   return $s . $MBI->_str($x->{_n}) if $MBI->_is_one($x->{_d});
  364.   $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d});
  365.   }
  366.  
  367. sub bsstr
  368.   {
  369.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  370.  
  371.   if ($x->{sign} !~ /^[+-]$/)        # inf, NaN etc
  372.     {
  373.     my $s = $x->{sign}; $s =~ s/^\+//;     # +inf => inf
  374.     return $s;
  375.     }
  376.   
  377.   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';    # +3 vs 3
  378.   $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d});
  379.   }
  380.  
  381. sub bnorm
  382.   {
  383.   # reduce the number to the shortest form
  384.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  385.  
  386.   # Both parts must be objects of whatever we are using today.
  387.   # Second check because Calc.pm has ARRAY res as unblessed objects.
  388.   if (ref($x->{_n}) ne $MBI && ref($x->{_n}) ne 'ARRAY')
  389.     {
  390.     require Carp; Carp::croak ("n is not $MBI but (".ref($x->{_n}).') in bnorm()');
  391.     }
  392.   if (ref($x->{_d}) ne $MBI && ref($x->{_d}) ne 'ARRAY')
  393.     {
  394.     require Carp; Carp::croak ("d is not $MBI but (".ref($x->{_d}).') in bnorm()');
  395.     }
  396.  
  397.   # no normalize for NaN, inf etc.
  398.   return $x if $x->{sign} !~ /^[+-]$/;
  399.  
  400.   # normalize zeros to 0/1
  401.   if ($MBI->_is_zero($x->{_n}))
  402.     {
  403.     $x->{sign} = '+';                    # never leave a -0
  404.     $x->{_d} = $MBI->_one() unless $MBI->_is_one($x->{_d});
  405.     return $x;
  406.     }
  407.  
  408.   return $x if $MBI->_is_one($x->{_d});            # no need to reduce
  409.  
  410.   # reduce other numbers
  411.   my $gcd = $MBI->_copy($x->{_n});
  412.   $gcd = $MBI->_gcd($gcd,$x->{_d});
  413.   
  414.   if (!$MBI->_is_one($gcd))
  415.     {
  416.     $x->{_n} = $MBI->_div($x->{_n},$gcd);
  417.     $x->{_d} = $MBI->_div($x->{_d},$gcd);
  418.     }
  419.   $x;
  420.   }
  421.  
  422. ##############################################################################
  423. # sign manipulation
  424.  
  425. sub bneg
  426.   {
  427.   # (BRAT or num_str) return BRAT
  428.   # negate number or make a negated number from string
  429.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  430.  
  431.   return $x if $x->modify('bneg');
  432.  
  433.   # for +0 dont negate (to have always normalized +0). Does nothing for 'NaN'
  434.   $x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $MBI->_is_zero($x->{_n}));
  435.   $x;
  436.   }
  437.  
  438. ##############################################################################
  439. # special values
  440.  
  441. sub _bnan
  442.   {
  443.   # used by parent class bnan() to initialize number to NaN
  444.   my $self = shift;
  445.  
  446.   if ($_trap_nan)
  447.     {
  448.     require Carp;
  449.     my $class = ref($self);
  450.     # "$self" below will stringify the object, this blows up if $self is a
  451.     # partial object (happens under trap_nan), so fix it beforehand
  452.     $self->{_d} = $MBI->_zero() unless defined $self->{_d};
  453.     $self->{_n} = $MBI->_zero() unless defined $self->{_n};
  454.     Carp::croak ("Tried to set $self to NaN in $class\::_bnan()");
  455.     }
  456.   $self->{_n} = $MBI->_zero();
  457.   $self->{_d} = $MBI->_zero();
  458.   }
  459.  
  460. sub _binf
  461.   {
  462.   # used by parent class bone() to initialize number to +inf/-inf
  463.   my $self = shift;
  464.  
  465.   if ($_trap_inf)
  466.     {
  467.     require Carp;
  468.     my $class = ref($self);
  469.     # "$self" below will stringify the object, this blows up if $self is a
  470.     # partial object (happens under trap_nan), so fix it beforehand
  471.     $self->{_d} = $MBI->_zero() unless defined $self->{_d};
  472.     $self->{_n} = $MBI->_zero() unless defined $self->{_n};
  473.     Carp::croak ("Tried to set $self to inf in $class\::_binf()");
  474.     }
  475.   $self->{_n} = $MBI->_zero();
  476.   $self->{_d} = $MBI->_zero();
  477.   }
  478.  
  479. sub _bone
  480.   {
  481.   # used by parent class bone() to initialize number to +1/-1
  482.   my $self = shift;
  483.   $self->{_n} = $MBI->_one();
  484.   $self->{_d} = $MBI->_one();
  485.   }
  486.  
  487. sub _bzero
  488.   {
  489.   # used by parent class bzero() to initialize number to 0
  490.   my $self = shift;
  491.   $self->{_n} = $MBI->_zero();
  492.   $self->{_d} = $MBI->_one();
  493.   }
  494.  
  495. ##############################################################################
  496. # mul/add/div etc
  497.  
  498. sub badd
  499.   {
  500.   # add two rational numbers
  501.  
  502.   # set up parameters
  503.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  504.   # objectify is costly, so avoid it
  505.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  506.     {
  507.     ($self,$x,$y,@r) = objectify(2,@_);
  508.     }
  509.  
  510.   # +inf + +inf => +inf,  -inf + -inf => -inf
  511.   return $x->binf(substr($x->{sign},0,1))
  512.     if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
  513.  
  514.   # +inf + -inf or -inf + +inf => NaN
  515.   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
  516.  
  517.   #  1   1    gcd(3,4) = 1    1*3 + 1*4    7
  518.   #  - + -                  = --------- = --                 
  519.   #  4   3                      4*3       12
  520.  
  521.   # we do not compute the gcd() here, but simple do:
  522.   #  5   7    5*3 + 7*4   43
  523.   #  - + -  = --------- = --                 
  524.   #  4   3       4*3      12
  525.  
  526.   # and bnorm() will then take care of the rest
  527.  
  528.   # 5 * 3
  529.   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d});
  530.  
  531.   # 7 * 4
  532.   my $m = $MBI->_mul( $MBI->_copy( $y->{_n} ), $x->{_d} );
  533.  
  534.   # 5 * 3 + 7 * 4
  535.   ($x->{_n}, $x->{sign}) = _e_add( $x->{_n}, $m, $x->{sign}, $y->{sign});
  536.  
  537.   # 4 * 3
  538.   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d});
  539.  
  540.   # normalize result, and possible round
  541.   $x->bnorm()->round(@r);
  542.   }
  543.  
  544. sub bsub
  545.   {
  546.   # subtract two rational numbers
  547.  
  548.   # set up parameters
  549.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  550.   # objectify is costly, so avoid it
  551.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  552.     {
  553.     ($self,$x,$y,@r) = objectify(2,@_);
  554.     }
  555.  
  556.   # flip sign of $x, call badd(), then flip sign of result
  557.   $x->{sign} =~ tr/+-/-+/
  558.     unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});    # not -0
  559.   $x->badd($y,@r);                # does norm and round
  560.   $x->{sign} =~ tr/+-/-+/ 
  561.     unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});    # not -0
  562.   $x;
  563.   }
  564.  
  565. sub bmul
  566.   {
  567.   # multiply two rational numbers
  568.   
  569.   # set up parameters
  570.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  571.   # objectify is costly, so avoid it
  572.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  573.     {
  574.     ($self,$x,$y,@r) = objectify(2,@_);
  575.     }
  576.  
  577.   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
  578.  
  579.   # inf handling
  580.   if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
  581.     {
  582.     return $x->bnan() if $x->is_zero() || $y->is_zero();
  583.     # result will always be +-inf:
  584.     # +inf * +/+inf => +inf, -inf * -/-inf => +inf
  585.     # +inf * -/-inf => -inf, -inf * +/+inf => -inf
  586.     return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
  587.     return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
  588.     return $x->binf('-');
  589.     }
  590.  
  591.   # x== 0 # also: or y == 1 or y == -1
  592.   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
  593.  
  594.   # XXX TODO:
  595.   # According to Knuth, this can be optimized by doing gcd twice (for d and n)
  596.   # and reducing in one step. This would save us the bnorm() at the end.
  597.  
  598.   #  1   2    1 * 2    2    1
  599.   #  - * - =  -----  = -  = -
  600.   #  4   3    4 * 3    12   6
  601.   
  602.   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_n});
  603.   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d});
  604.  
  605.   # compute new sign
  606.   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
  607.  
  608.   $x->bnorm()->round(@r);
  609.   }
  610.  
  611. sub bdiv
  612.   {
  613.   # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
  614.   # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
  615.  
  616.   # set up parameters
  617.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  618.   # objectify is costly, so avoid it
  619.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  620.     {
  621.     ($self,$x,$y,@r) = objectify(2,@_);
  622.     }
  623.  
  624.   return $self->_div_inf($x,$y)
  625.    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
  626.  
  627.   # x== 0 # also: or y == 1 or y == -1
  628.   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
  629.  
  630.   # XXX TODO: list context, upgrade
  631.   # According to Knuth, this can be optimized by doing gcd twice (for d and n)
  632.   # and reducing in one step. This would save us the bnorm() at the end.
  633.  
  634.   # 1     1    1   3
  635.   # -  /  - == - * -
  636.   # 4     3    4   1
  637.   
  638.   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d});
  639.   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_n});
  640.  
  641.   # compute new sign 
  642.   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
  643.  
  644.   $x->bnorm()->round(@r);
  645.   $x;
  646.   }
  647.  
  648. sub bmod
  649.   {
  650.   # compute "remainder" (in Perl way) of $x / $y
  651.  
  652.   # set up parameters
  653.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  654.   # objectify is costly, so avoid it
  655.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  656.     {
  657.     ($self,$x,$y,@r) = objectify(2,@_);
  658.     }
  659.  
  660.   return $self->_div_inf($x,$y)
  661.    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
  662.  
  663.   return $x if $x->is_zero();           # 0 / 7 = 0, mod 0
  664.  
  665.   # compute $x - $y * floor($x/$y), keeping the sign of $x
  666.  
  667.   # copy x to u, make it positive and then do a normal division ($u/$y)
  668.   my $u = bless { sign => '+' }, $self;
  669.   $u->{_n} = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d} );
  670.   $u->{_d} = $MBI->_mul( $MBI->_copy($x->{_d}), $y->{_n} );
  671.   
  672.   # compute floor(u)
  673.   if (! $MBI->_is_one($u->{_d}))
  674.     {
  675.     $u->{_n} = $MBI->_div($u->{_n},$u->{_d});    # 22/7 => 3/1 w/ truncate
  676.     # no need to set $u->{_d} to 1, since below we set it to $y->{_d} anyway
  677.     }
  678.   
  679.   # now compute $y * $u
  680.   $u->{_d} = $MBI->_copy($y->{_d});        # 1 * $y->{_d}, see floor above
  681.   $u->{_n} = $MBI->_mul($u->{_n},$y->{_n});
  682.  
  683.   my $xsign = $x->{sign}; $x->{sign} = '+';    # remember sign and make x positive
  684.   # compute $x - $u
  685.   $x->bsub($u);
  686.   $x->{sign} = $xsign;                # put sign back
  687.  
  688.   $x->bnorm()->round(@r);
  689.   }
  690.  
  691. ##############################################################################
  692. # bdec/binc
  693.  
  694. sub bdec
  695.   {
  696.   # decrement value (subtract 1)
  697.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  698.  
  699.   return $x if $x->{sign} !~ /^[+-]$/;    # NaN, inf, -inf
  700.  
  701.   if ($x->{sign} eq '-')
  702.     {
  703.     $x->{_n} = $MBI->_add( $x->{_n}, $x->{_d});        # -5/2 => -7/2
  704.     }
  705.   else
  706.     {
  707.     if ($MBI->_acmp($x->{_n},$x->{_d}) < 0)        # n < d?
  708.       {
  709.       # 1/3 -- => -2/3
  710.       $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n});
  711.       $x->{sign} = '-';
  712.       }
  713.     else
  714.       {
  715.       $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d});     # 5/2 => 3/2
  716.       }
  717.     }
  718.   $x->bnorm()->round(@r);
  719.   }
  720.  
  721. sub binc
  722.   {
  723.   # increment value (add 1)
  724.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  725.   
  726.   return $x if $x->{sign} !~ /^[+-]$/;    # NaN, inf, -inf
  727.  
  728.   if ($x->{sign} eq '-')
  729.     {
  730.     if ($MBI->_acmp($x->{_n},$x->{_d}) < 0)
  731.       {
  732.       # -1/3 ++ => 2/3 (overflow at 0)
  733.       $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n});
  734.       $x->{sign} = '+';
  735.       }
  736.     else
  737.       {
  738.       $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d});     # -5/2 => -3/2
  739.       }
  740.     }
  741.   else
  742.     {
  743.     $x->{_n} = $MBI->_add($x->{_n},$x->{_d});        # 5/2 => 7/2
  744.     }
  745.   $x->bnorm()->round(@r);
  746.   }
  747.  
  748. ##############################################################################
  749. # is_foo methods (the rest is inherited)
  750.  
  751. sub is_int
  752.   {
  753.   # return true if arg (BRAT or num_str) is an integer
  754.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  755.  
  756.   return 1 if ($x->{sign} =~ /^[+-]$/) &&    # NaN and +-inf aren't
  757.     $MBI->_is_one($x->{_d});            # x/y && y != 1 => no integer
  758.   0;
  759.   }
  760.  
  761. sub is_zero
  762.   {
  763.   # return true if arg (BRAT or num_str) is zero
  764.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  765.  
  766.   return 1 if $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});
  767.   0;
  768.   }
  769.  
  770. sub is_one
  771.   {
  772.   # return true if arg (BRAT or num_str) is +1 or -1 if signis given
  773.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  774.  
  775.   my $sign = $_[2] || ''; $sign = '+' if $sign ne '-';
  776.   return 1
  777.    if ($x->{sign} eq $sign && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d}));
  778.   0;
  779.   }
  780.  
  781. sub is_odd
  782.   {
  783.   # return true if arg (BFLOAT or num_str) is odd or false if even
  784.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  785.  
  786.   return 1 if ($x->{sign} =~ /^[+-]$/) &&        # NaN & +-inf aren't
  787.     ($MBI->_is_one($x->{_d}) && $MBI->_is_odd($x->{_n})); # x/2 is not, but 3/1
  788.   0;
  789.   }
  790.  
  791. sub is_even
  792.   {
  793.   # return true if arg (BINT or num_str) is even or false if odd
  794.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  795.  
  796.   return 0 if $x->{sign} !~ /^[+-]$/;            # NaN & +-inf aren't
  797.   return 1 if ($MBI->_is_one($x->{_d})            # x/3 is never
  798.      && $MBI->_is_even($x->{_n}));            # but 4/1 is
  799.   0;
  800.   }
  801.  
  802. ##############################################################################
  803. # parts() and friends
  804.  
  805. sub numerator
  806.   {
  807.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  808.  
  809.   # NaN, inf, -inf
  810.   return Math::BigInt->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
  811.  
  812.   my $n = Math::BigInt->new($MBI->_str($x->{_n})); $n->{sign} = $x->{sign};
  813.   $n;
  814.   }
  815.  
  816. sub denominator
  817.   {
  818.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  819.  
  820.   # NaN
  821.   return Math::BigInt->new($x->{sign}) if $x->{sign} eq 'NaN';
  822.   # inf, -inf
  823.   return Math::BigInt->bone() if $x->{sign} !~ /^[+-]$/;
  824.   
  825.   Math::BigInt->new($MBI->_str($x->{_d}));
  826.   }
  827.  
  828. sub parts
  829.   {
  830.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  831.  
  832.   my $c = 'Math::BigInt';
  833.  
  834.   return ($c->bnan(),$c->bnan()) if $x->{sign} eq 'NaN';
  835.   return ($c->binf(),$c->binf()) if $x->{sign} eq '+inf';
  836.   return ($c->binf('-'),$c->binf()) if $x->{sign} eq '-inf';
  837.  
  838.   my $n = $c->new( $MBI->_str($x->{_n}));
  839.   $n->{sign} = $x->{sign};
  840.   my $d = $c->new( $MBI->_str($x->{_d}));
  841.   ($n,$d);
  842.   }
  843.  
  844. sub length
  845.   {
  846.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  847.  
  848.   return $nan unless $x->is_int();
  849.   $MBI->_len($x->{_n});                # length(-123/1) => length(123)
  850.   }
  851.  
  852. sub digit
  853.   {
  854.   my ($self,$x,$n) = ref($_[0]) ? (undef,$_[0],$_[1]) : objectify(1,@_);
  855.  
  856.   return $nan unless $x->is_int();
  857.   $MBI->_digit($x->{_n},$n || 0);        # digit(-123/1,2) => digit(123,2)
  858.   }
  859.  
  860. ##############################################################################
  861. # special calc routines
  862.  
  863. sub bceil
  864.   {
  865.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  866.  
  867.   return $x if $x->{sign} !~ /^[+-]$/ ||    # not for NaN, inf
  868.             $MBI->_is_one($x->{_d});        # 22/1 => 22, 0/1 => 0
  869.  
  870.   $x->{_n} = $MBI->_div($x->{_n},$x->{_d});    # 22/7 => 3/1 w/ truncate
  871.   $x->{_d} = $MBI->_one();            # d => 1
  872.   $x->{_n} = $MBI->_inc($x->{_n})
  873.     if $x->{sign} eq '+';            # +22/7 => 4/1
  874.   $x->{sign} = '+' if $MBI->_is_zero($x->{_n});    # -0 => 0
  875.   $x;
  876.   }
  877.  
  878. sub bfloor
  879.   {
  880.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  881.  
  882.   return $x if $x->{sign} !~ /^[+-]$/ ||    # not for NaN, inf
  883.             $MBI->_is_one($x->{_d});        # 22/1 => 22, 0/1 => 0
  884.  
  885.   $x->{_n} = $MBI->_div($x->{_n},$x->{_d});    # 22/7 => 3/1 w/ truncate
  886.   $x->{_d} = $MBI->_one();            # d => 1
  887.   $x->{_n} = $MBI->_inc($x->{_n})
  888.     if $x->{sign} eq '-';            # -22/7 => -4/1
  889.   $x;
  890.   }
  891.  
  892. sub bfac
  893.   {
  894.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  895.  
  896.   # if $x is not an integer
  897.   if (($x->{sign} ne '+') || (!$MBI->_is_one($x->{_d})))
  898.     {
  899.     return $x->bnan();
  900.     }
  901.  
  902.   $x->{_n} = $MBI->_fac($x->{_n});
  903.   # since _d is 1, we don't need to reduce/norm the result
  904.   $x->round(@r);
  905.   }
  906.  
  907. sub bpow
  908.   {
  909.   # power ($x ** $y)
  910.  
  911.   # set up parameters
  912.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  913.   # objectify is costly, so avoid it
  914.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  915.     {
  916.     ($self,$x,$y,@r) = objectify(2,@_);
  917.     }
  918.  
  919.   return $x if $x->{sign} =~ /^[+-]inf$/;       # -inf/+inf ** x
  920.   return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
  921.   return $x->bone(@r) if $y->is_zero();
  922.   return $x->round(@r) if $x->is_one() || $y->is_one();
  923.  
  924.   if ($x->{sign} eq '-' && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d}))
  925.     {
  926.     # if $x == -1 and odd/even y => +1/-1
  927.     return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
  928.     # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
  929.     }
  930.   # 1 ** -y => 1 / (1 ** |y|)
  931.   # so do test for negative $y after above's clause
  932.  
  933.   return $x->round(@r) if $x->is_zero();  # 0**y => 0 (if not y <= 0)
  934.  
  935.   # shortcut y/1 (and/or x/1)
  936.   if ($MBI->_is_one($y->{_d}))
  937.     {
  938.     # shortcut for x/1 and y/1
  939.     if ($MBI->_is_one($x->{_d}))
  940.       {
  941.       $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});        # x/1 ** y/1 => (x ** y)/1
  942.       if ($y->{sign} eq '-')
  943.         {
  944.         # 0.2 ** -3 => 1/(0.2 ** 3)
  945.         ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});    # swap
  946.         }
  947.       # correct sign; + ** + => +
  948.       if ($x->{sign} eq '-')
  949.         {
  950.         # - * - => +, - * - * - => -
  951.         $x->{sign} = '+' if $MBI->_is_even($y->{_n});    
  952.         }
  953.       return $x->round(@r);
  954.       }
  955.     # x/z ** y/1
  956.     $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});        # 5/2 ** y/1 => 5 ** y / 2 ** y
  957.     $x->{_d} = $MBI->_pow($x->{_d},$y->{_n});
  958.     if ($y->{sign} eq '-')
  959.       {
  960.       # 0.2 ** -3 => 1/(0.2 ** 3)
  961.       ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});    # swap
  962.       }
  963.     # correct sign; + ** + => +
  964.     if ($x->{sign} eq '-')
  965.       {
  966.       # - * - => +, - * - * - => -
  967.       $x->{sign} = '+' if $MBI->_is_even($y->{_n});    
  968.       }
  969.     return $x->round(@r);
  970.     }
  971.  
  972.   # regular calculation (this is wrong for d/e ** f/g)
  973.   my $pow2 = $self->bone();
  974.   my $y1 = $MBI->_div ( $MBI->_copy($y->{_n}), $y->{_d});
  975.   my $two = $MBI->_two();
  976.  
  977.   while (!$MBI->_is_one($y1))
  978.     {
  979.     $pow2->bmul($x) if $MBI->_is_odd($y1);
  980.     $MBI->_div($y1, $two);
  981.     $x->bmul($x);
  982.     }
  983.   $x->bmul($pow2) unless $pow2->is_one();
  984.   # n ** -x => 1/n ** x
  985.   ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-'; 
  986.   $x->bnorm()->round(@r);
  987.   }
  988.  
  989. sub blog
  990.   {
  991.   # set up parameters
  992.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  993.  
  994.   # objectify is costly, so avoid it
  995.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  996.     {
  997.     ($self,$x,$y,@r) = objectify(2,$class,@_);
  998.     }
  999.  
  1000.   # blog(1,Y) => 0
  1001.   return $x->bzero() if $x->is_one() && $y->{sign} eq '+';
  1002.  
  1003.   # $x <= 0 => NaN
  1004.   return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+';
  1005.  
  1006.   if ($x->is_int() && $y->is_int())
  1007.     {
  1008.     return $self->new($x->as_number()->blog($y->as_number(),@r));
  1009.     }
  1010.  
  1011.   # do it with floats
  1012.   $x->_new_from_float( $x->_as_float()->blog(Math::BigFloat->new("$y"),@r) );
  1013.   }
  1014.  
  1015. sub _float_from_part
  1016.   {
  1017.   my $x = shift;
  1018.  
  1019.   my $f = Math::BigFloat->bzero();
  1020.   $f->{_m} = $MBI->_copy($x);
  1021.   $f->{_e} = $MBI->_zero();
  1022.  
  1023.   $f;
  1024.   }
  1025.  
  1026. sub _as_float
  1027.   {
  1028.   my $x = shift;
  1029.  
  1030.   local $Math::BigFloat::upgrade = undef;
  1031.   local $Math::BigFloat::accuracy = undef;
  1032.   local $Math::BigFloat::precision = undef;
  1033.   # 22/7 => 3.142857143..
  1034.  
  1035.   my $a = $x->accuracy() || 0;
  1036.   if ($a != 0 || !$MBI->_is_one($x->{_d}))
  1037.     {
  1038.     # n/d
  1039.     return Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}))->bdiv( $MBI->_str($x->{_d}), $x->accuracy());
  1040.     }
  1041.   # just n
  1042.   Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}));
  1043.   }
  1044.  
  1045. sub broot
  1046.   {
  1047.   # set up parameters
  1048.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  1049.   # objectify is costly, so avoid it
  1050.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  1051.     {
  1052.     ($self,$x,$y,@r) = objectify(2,@_);
  1053.     }
  1054.  
  1055.   if ($x->is_int() && $y->is_int())
  1056.     {
  1057.     return $self->new($x->as_number()->broot($y->as_number(),@r));
  1058.     }
  1059.  
  1060.   # do it with floats
  1061.   $x->_new_from_float( $x->_as_float()->broot($y,@r) );
  1062.   }
  1063.  
  1064. sub bmodpow
  1065.   {
  1066.   # set up parameters
  1067.   my ($self,$x,$y,$m,@r) = (ref($_[0]),@_);
  1068.   # objectify is costly, so avoid it
  1069.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  1070.     {
  1071.     ($self,$x,$y,$m,@r) = objectify(3,@_);
  1072.     }
  1073.  
  1074.   # $x or $y or $m are NaN or +-inf => NaN
  1075.   return $x->bnan()
  1076.    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ ||
  1077.    $m->{sign} !~ /^[+-]$/;
  1078.  
  1079.   if ($x->is_int() && $y->is_int() && $m->is_int())
  1080.     {
  1081.     return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r));
  1082.     }
  1083.  
  1084.   warn ("bmodpow() not fully implemented");
  1085.   $x->bnan();
  1086.   }
  1087.  
  1088. sub bmodinv
  1089.   {
  1090.   # set up parameters
  1091.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  1092.   # objectify is costly, so avoid it
  1093.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  1094.     {
  1095.     ($self,$x,$y,@r) = objectify(2,@_);
  1096.     }
  1097.  
  1098.   # $x or $y are NaN or +-inf => NaN
  1099.   return $x->bnan() 
  1100.    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/;
  1101.  
  1102.   if ($x->is_int() && $y->is_int())
  1103.     {
  1104.     return $self->new($x->as_number()->bmodinv($y->as_number(),@r));
  1105.     }
  1106.  
  1107.   warn ("bmodinv() not fully implemented");
  1108.   $x->bnan();
  1109.   }
  1110.  
  1111. sub bsqrt
  1112.   {
  1113.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  1114.  
  1115.   return $x->bnan() if $x->{sign} !~ /^[+]/;    # NaN, -inf or < 0
  1116.   return $x if $x->{sign} eq '+inf';            # sqrt(inf) == inf
  1117.   return $x->round(@r) if $x->is_zero() || $x->is_one();
  1118.  
  1119.   local $Math::BigFloat::upgrade = undef;
  1120.   local $Math::BigFloat::downgrade = undef;
  1121.   local $Math::BigFloat::precision = undef;
  1122.   local $Math::BigFloat::accuracy = undef;
  1123.   local $Math::BigInt::upgrade = undef;
  1124.   local $Math::BigInt::precision = undef;
  1125.   local $Math::BigInt::accuracy = undef;
  1126.  
  1127.   $x->{_n} = _float_from_part( $x->{_n} )->bsqrt();
  1128.   $x->{_d} = _float_from_part( $x->{_d} )->bsqrt();
  1129.  
  1130.   # XXX TODO: we probably can optimze this:
  1131.  
  1132.   # if sqrt(D) was not integer
  1133.   if ($x->{_d}->{_es} ne '+')
  1134.     {
  1135.     $x->{_n}->blsft($x->{_d}->exponent()->babs(),10);    # 7.1/4.51 => 7.1/45.1
  1136.     $x->{_d} = $MBI->_copy( $x->{_d}->{_m} );        # 7.1/45.1 => 71/45.1
  1137.     }
  1138.   # if sqrt(N) was not integer
  1139.   if ($x->{_n}->{_es} ne '+')
  1140.     {
  1141.     $x->{_d}->blsft($x->{_n}->exponent()->babs(),10);    # 71/45.1 => 710/45.1
  1142.     $x->{_n} = $MBI->_copy( $x->{_n}->{_m} );        # 710/45.1 => 710/451
  1143.     }
  1144.  
  1145.   # convert parts to $MBI again 
  1146.   $x->{_n} = $MBI->_lsft( $MBI->_copy( $x->{_n}->{_m} ), $x->{_n}->{_e}, 10)
  1147.     if ref($x->{_n}) ne $MBI && ref($x->{_n}) ne 'ARRAY';
  1148.   $x->{_d} = $MBI->_lsft( $MBI->_copy( $x->{_d}->{_m} ), $x->{_d}->{_e}, 10)
  1149.     if ref($x->{_d}) ne $MBI && ref($x->{_d}) ne 'ARRAY';
  1150.  
  1151.   $x->bnorm()->round(@r);
  1152.   }
  1153.  
  1154. sub blsft
  1155.   {
  1156.   my ($self,$x,$y,$b,@r) = objectify(3,@_);
  1157.  
  1158.   $b = 2 unless defined $b;
  1159.   $b = $self->new($b) unless ref ($b);
  1160.   $x->bmul( $b->copy()->bpow($y), @r);
  1161.   $x;
  1162.   }
  1163.  
  1164. sub brsft
  1165.   {
  1166.   my ($self,$x,$y,$b,@r) = objectify(3,@_);
  1167.  
  1168.   $b = 2 unless defined $b;
  1169.   $b = $self->new($b) unless ref ($b);
  1170.   $x->bdiv( $b->copy()->bpow($y), @r);
  1171.   $x;
  1172.   }
  1173.  
  1174. ##############################################################################
  1175. # round
  1176.  
  1177. sub round
  1178.   {
  1179.   $_[0];
  1180.   }
  1181.  
  1182. sub bround
  1183.   {
  1184.   $_[0];
  1185.   }
  1186.  
  1187. sub bfround
  1188.   {
  1189.   $_[0];
  1190.   }
  1191.  
  1192. ##############################################################################
  1193. # comparing
  1194.  
  1195. sub bcmp
  1196.   {
  1197.   # compare two signed numbers 
  1198.   
  1199.   # set up parameters
  1200.   my ($self,$x,$y) = (ref($_[0]),@_);
  1201.   # objectify is costly, so avoid it
  1202.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  1203.     {
  1204.     ($self,$x,$y) = objectify(2,@_);
  1205.     }
  1206.  
  1207.   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
  1208.     {
  1209.     # handle +-inf and NaN
  1210.     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
  1211.     return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
  1212.     return +1 if $x->{sign} eq '+inf';
  1213.     return -1 if $x->{sign} eq '-inf';
  1214.     return -1 if $y->{sign} eq '+inf';
  1215.     return +1;
  1216.     }
  1217.   # check sign for speed first
  1218.   return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';   # does also 0 <=> -y
  1219.   return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';  # does also -x <=> 0
  1220.  
  1221.   # shortcut
  1222.   my $xz = $MBI->_is_zero($x->{_n});
  1223.   my $yz = $MBI->_is_zero($y->{_n});
  1224.   return 0 if $xz && $yz;                               # 0 <=> 0
  1225.   return -1 if $xz && $y->{sign} eq '+';                # 0 <=> +y
  1226.   return 1 if $yz && $x->{sign} eq '+';                 # +x <=> 0
  1227.  
  1228.   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
  1229.   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
  1230.  
  1231.   my $cmp = $MBI->_acmp($t,$u);                # signs are equal
  1232.   $cmp = -$cmp if $x->{sign} eq '-';            # both are '-' => reverse
  1233.   $cmp;
  1234.   }
  1235.  
  1236. sub bacmp
  1237.   {
  1238.   # compare two numbers (as unsigned)
  1239.  
  1240.   # set up parameters
  1241.   my ($self,$x,$y) = (ref($_[0]),@_);
  1242.   # objectify is costly, so avoid it
  1243.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  1244.     {
  1245.     ($self,$x,$y) = objectify(2,$class,@_);
  1246.     }
  1247.  
  1248.   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
  1249.     {
  1250.     # handle +-inf and NaN
  1251.     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
  1252.     return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
  1253.     return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
  1254.     return -1;
  1255.     }
  1256.  
  1257.   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
  1258.   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
  1259.   $MBI->_acmp($t,$u);                    # ignore signs
  1260.   }
  1261.  
  1262. ##############################################################################
  1263. # output conversation
  1264.  
  1265. sub numify
  1266.   {
  1267.   # convert 17/8 => float (aka 2.125)
  1268.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  1269.  
  1270.   return $x->bstr() if $x->{sign} !~ /^[+-]$/;    # inf, NaN, etc
  1271.  
  1272.   # N/1 => N
  1273.   my $neg = ''; $neg = '-' if $x->{sign} eq '-';
  1274.   return $neg . $MBI->_num($x->{_n}) if $MBI->_is_one($x->{_d});
  1275.  
  1276.   $x->_as_float()->numify() + 0.0;
  1277.   }
  1278.  
  1279. sub as_number
  1280.   {
  1281.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  1282.  
  1283.   return Math::BigInt->new($x) if $x->{sign} !~ /^[+-]$/;    # NaN, inf etc
  1284.  
  1285.   my $u = Math::BigInt->bzero();
  1286.   $u->{sign} = $x->{sign};
  1287.   $u->{value} = $MBI->_div( $MBI->_copy($x->{_n}), $x->{_d});    # 22/7 => 3
  1288.   $u;
  1289.   }
  1290.  
  1291. sub as_bin
  1292.   {
  1293.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  1294.  
  1295.   return $x unless $x->is_int();
  1296.  
  1297.   my $s = $x->{sign}; $s = '' if $s eq '+';
  1298.   $s . $MBI->_as_bin($x->{_n});
  1299.   }
  1300.  
  1301. sub as_hex
  1302.   {
  1303.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  1304.  
  1305.   return $x unless $x->is_int();
  1306.  
  1307.   my $s = $x->{sign}; $s = '' if $s eq '+';
  1308.   $s . $MBI->_as_hex($x->{_n});
  1309.   }
  1310.  
  1311. ##############################################################################
  1312. # import
  1313.  
  1314. sub import
  1315.   {
  1316.   my $self = shift;
  1317.   my $l = scalar @_;
  1318.   my $lib = ''; my @a;
  1319.  
  1320.   for ( my $i = 0; $i < $l ; $i++)
  1321.     {
  1322.     if ( $_[$i] eq ':constant' )
  1323.       {
  1324.       # this rest causes overlord er load to step in
  1325.       overload::constant float => sub { $self->new(shift); };
  1326.       }
  1327. #    elsif ($_[$i] eq 'upgrade')
  1328. #      {
  1329. #     # this causes upgrading
  1330. #      $upgrade = $_[$i+1];        # or undef to disable
  1331. #      $i++;
  1332. #      }
  1333.     elsif ($_[$i] eq 'downgrade')
  1334.       {
  1335.       # this causes downgrading
  1336.       $downgrade = $_[$i+1];        # or undef to disable
  1337.       $i++;
  1338.       }
  1339.     elsif ($_[$i] eq 'lib')
  1340.       {
  1341.       $lib = $_[$i+1] || '';        # default Calc
  1342.       $i++;
  1343.       }
  1344.     elsif ($_[$i] eq 'with')
  1345.       {
  1346.       # this argument is no longer used
  1347.       #$MBI = $_[$i+1] || 'Math::BigInt::Calc';    # default Math::BigInt::Calc
  1348.       $i++;
  1349.       }
  1350.     else
  1351.       {
  1352.       push @a, $_[$i];
  1353.       }
  1354.     }
  1355.   require Math::BigInt;
  1356.  
  1357.   # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still have GMP
  1358.   if ($lib ne '')
  1359.     {
  1360.     my @c = split /\s*,\s*/, $lib;
  1361.     foreach (@c)
  1362.       {
  1363.       $_ =~ tr/a-zA-Z0-9://cd;                    # limit to sane characters
  1364.       }
  1365.     $lib = join(",", @c);
  1366.     }
  1367.   my @import = ('objectify');
  1368.   push @import, lib => $lib if $lib ne '';
  1369.  
  1370.   # MBI already loaded, so feed it our lib arguments
  1371.   Math::BigInt->import( @import );
  1372.  
  1373.   $MBI = Math::BigFloat->config()->{lib};
  1374.  
  1375.   # register us with MBI to get notified of future lib changes
  1376.   Math::BigInt::_register_callback( $self, sub { $MBI = $_[0]; } );
  1377.   
  1378.   # any non :constant stuff is handled by our parent, Exporter (loaded
  1379.   # by Math::BigFloat, even if @_ is empty, to give it a chance
  1380.   $self->SUPER::import(@a);             # for subclasses
  1381.   $self->export_to_level(1,$self,@a);   # need this, too
  1382.   }
  1383.  
  1384. 1;
  1385.  
  1386. __END__
  1387.  
  1388. =head1 NAME
  1389.  
  1390. Math::BigRat - Arbitrary big rational numbers
  1391.  
  1392. =head1 SYNOPSIS
  1393.  
  1394.     use Math::BigRat;
  1395.  
  1396.     my $x = Math::BigRat->new('3/7'); $x += '5/9';
  1397.  
  1398.     print $x->bstr(),"\n";
  1399.       print $x ** 2,"\n";
  1400.  
  1401.     my $y = Math::BigRat->new('inf');
  1402.     print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n";
  1403.  
  1404.     my $z = Math::BigRat->new(144); $z->bsqrt();
  1405.  
  1406. =head1 DESCRIPTION
  1407.  
  1408. Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
  1409. for arbitrary big rational numbers.
  1410.  
  1411. =head2 MATH LIBRARY
  1412.  
  1413. Math with the numbers is done (by default) by a module called
  1414. Math::BigInt::Calc. This is equivalent to saying:
  1415.  
  1416.     use Math::BigRat lib => 'Calc';
  1417.  
  1418. You can change this by using:
  1419.  
  1420.     use Math::BigRat lib => 'BitVect';
  1421.  
  1422. The following would first try to find Math::BigInt::Foo, then
  1423. Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
  1424.  
  1425.     use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
  1426.  
  1427. Calc.pm uses as internal format an array of elements of some decimal base
  1428. (usually 1e7, but this might be different for some systems) with the least
  1429. significant digit first, while BitVect.pm uses a bit vector of base 2, most
  1430. significant bit first. Other modules might use even different means of
  1431. representing the numbers. See the respective module documentation for further
  1432. details.
  1433.  
  1434. Currently the following replacement libraries exist, search for them at CPAN:
  1435.  
  1436.     Math::BigInt::BitVect
  1437.     Math::BigInt::GMP
  1438.     Math::BigInt::Pari
  1439.     Math::BigInt::FastCalc
  1440.  
  1441. =head1 METHODS
  1442.  
  1443. Any methods not listed here are dervied from Math::BigFloat (or
  1444. Math::BigInt), so make sure you check these two modules for further
  1445. information.
  1446.  
  1447. =head2 new()
  1448.  
  1449.     $x = Math::BigRat->new('1/3');
  1450.  
  1451. Create a new Math::BigRat object. Input can come in various forms:
  1452.  
  1453.     $x = Math::BigRat->new(123);                # scalars
  1454.     $x = Math::BigRat->new('inf');                # infinity
  1455.     $x = Math::BigRat->new('123.3');            # float
  1456.     $x = Math::BigRat->new('1/3');                # simple string
  1457.     $x = Math::BigRat->new('1 / 3');            # spaced
  1458.     $x = Math::BigRat->new('1 / 0.1');            # w/ floats
  1459.     $x = Math::BigRat->new(Math::BigInt->new(3));        # BigInt
  1460.     $x = Math::BigRat->new(Math::BigFloat->new('3.1'));    # BigFloat
  1461.     $x = Math::BigRat->new(Math::BigInt::Lite->new('2'));    # BigLite
  1462.  
  1463.     # You can also give D and N as different objects:
  1464.     $x = Math::BigRat->new(
  1465.         Math::BigInt->new(-123),
  1466.         Math::BigInt->new(7),
  1467.         );            # => -123/7
  1468.  
  1469. =head2 numerator()
  1470.  
  1471.     $n = $x->numerator();
  1472.  
  1473. Returns a copy of the numerator (the part above the line) as signed BigInt.
  1474.  
  1475. =head2 denominator()
  1476.     
  1477.     $d = $x->denominator();
  1478.  
  1479. Returns a copy of the denominator (the part under the line) as positive BigInt.
  1480.  
  1481. =head2 parts()
  1482.  
  1483.     ($n,$d) = $x->parts();
  1484.  
  1485. Return a list consisting of (signed) numerator and (unsigned) denominator as
  1486. BigInts.
  1487.  
  1488. =head2 as_int()
  1489.  
  1490.     $x = Math::BigRat->new('13/7');
  1491.     print $x->as_int(),"\n";        # '1'
  1492.  
  1493. Returns a copy of the object as BigInt, truncated to an integer.
  1494.  
  1495. C<as_number()> is an alias for C<as_int()>.
  1496.  
  1497. =head2 as_hex()
  1498.  
  1499.     $x = Math::BigRat->new('13');
  1500.     print $x->as_hex(),"\n";        # '0xd'
  1501.  
  1502. Returns the BigRat as hexadecimal string. Works only for integers. 
  1503.  
  1504. =head2 as_bin()
  1505.  
  1506.     $x = Math::BigRat->new('13');
  1507.     print $x->as_bin(),"\n";        # '0x1101'
  1508.  
  1509. Returns the BigRat as binary string. Works only for integers. 
  1510.  
  1511. =head2 bfac()
  1512.  
  1513.     $x->bfac();
  1514.  
  1515. Calculates the factorial of $x. For instance:
  1516.  
  1517.     print Math::BigRat->new('3/1')->bfac(),"\n";    # 1*2*3
  1518.     print Math::BigRat->new('5/1')->bfac(),"\n";    # 1*2*3*4*5
  1519.  
  1520. Works currently only for integers.
  1521.  
  1522. =head2 blog()
  1523.  
  1524. Is not yet implemented.
  1525.  
  1526. =head2 bround()/round()/bfround()
  1527.  
  1528. Are not yet implemented.
  1529.  
  1530. =head2 bmod()
  1531.  
  1532.     use Math::BigRat;
  1533.     my $x = Math::BigRat->new('7/4');
  1534.     my $y = Math::BigRat->new('4/3');
  1535.     print $x->bmod($y);
  1536.  
  1537. Set $x to the remainder of the division of $x by $y.
  1538.  
  1539. =head2 is_one()
  1540.  
  1541.     print "$x is 1\n" if $x->is_one();
  1542.  
  1543. Return true if $x is exactly one, otherwise false.
  1544.  
  1545. =head2 is_zero()
  1546.  
  1547.     print "$x is 0\n" if $x->is_zero();
  1548.  
  1549. Return true if $x is exactly zero, otherwise false.
  1550.  
  1551. =head2 is_pos()
  1552.  
  1553.     print "$x is >= 0\n" if $x->is_positive();
  1554.  
  1555. Return true if $x is positive (greater than or equal to zero), otherwise
  1556. false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
  1557.  
  1558. C<is_positive()> is an alias for C<is_pos()>.
  1559.  
  1560. =head2 is_neg()
  1561.  
  1562.     print "$x is < 0\n" if $x->is_negative();
  1563.  
  1564. Return true if $x is negative (smaller than zero), otherwise false. Please
  1565. note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
  1566.  
  1567. C<is_negative()> is an alias for C<is_neg()>.
  1568.  
  1569. =head2 is_int()
  1570.  
  1571.     print "$x is an integer\n" if $x->is_int();
  1572.  
  1573. Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
  1574. false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
  1575.  
  1576. =head2 is_odd()
  1577.  
  1578.     print "$x is odd\n" if $x->is_odd();
  1579.  
  1580. Return true if $x is odd, otherwise false.
  1581.  
  1582. =head2 is_even()
  1583.  
  1584.     print "$x is even\n" if $x->is_even();
  1585.  
  1586. Return true if $x is even, otherwise false.
  1587.  
  1588. =head2 bceil()
  1589.  
  1590.     $x->bceil();
  1591.  
  1592. Set $x to the next bigger integer value (e.g. truncate the number to integer
  1593. and then increment it by one).
  1594.  
  1595. =head2 bfloor()
  1596.     
  1597.     $x->bfloor();
  1598.  
  1599. Truncate $x to an integer value.
  1600.  
  1601. =head2 bsqrt()
  1602.     
  1603.     $x->bsqrt();
  1604.  
  1605. Calculate the square root of $x.
  1606.  
  1607. =head2 config
  1608.  
  1609.         use Data::Dumper;
  1610.  
  1611.         print Dumper ( Math::BigRat->config() );
  1612.         print Math::BigRat->config()->{lib},"\n";
  1613.  
  1614. Returns a hash containing the configuration, e.g. the version number, lib
  1615. loaded etc. The following hash keys are currently filled in with the
  1616. appropriate information.
  1617.  
  1618.         key             RO/RW   Description
  1619.                                 Example
  1620.         ============================================================
  1621.         lib             RO      Name of the Math library
  1622.                                 Math::BigInt::Calc
  1623.         lib_version     RO      Version of 'lib'
  1624.                                 0.30
  1625.         class           RO      The class of config you just called
  1626.                                 Math::BigRat
  1627.         version         RO      version number of the class you used
  1628.                                 0.10
  1629.         upgrade         RW      To which class numbers are upgraded
  1630.                                 undef
  1631.         downgrade       RW      To which class numbers are downgraded
  1632.                                 undef
  1633.         precision       RW      Global precision
  1634.                                 undef
  1635.         accuracy        RW      Global accuracy
  1636.                                 undef
  1637.         round_mode      RW      Global round mode
  1638.                                 even
  1639.         div_scale       RW      Fallback acccuracy for div
  1640.                                 40
  1641.         trap_nan        RW      Trap creation of NaN (undef = no)
  1642.                                 undef
  1643.         trap_inf        RW      Trap creation of +inf/-inf (undef = no)
  1644.                                 undef
  1645.  
  1646. By passing a reference to a hash you may set the configuration values. This
  1647. works only for values that a marked with a C<RW> above, anything else is
  1648. read-only.
  1649.  
  1650. =head1 BUGS
  1651.  
  1652. Some things are not yet implemented, or only implemented half-way:
  1653.  
  1654. =over 2
  1655.  
  1656. =item inf handling (partial)
  1657.  
  1658. =item NaN handling (partial)
  1659.  
  1660. =item rounding (not implemented except for bceil/bfloor)
  1661.  
  1662. =item $x ** $y where $y is not an integer
  1663.  
  1664. =item bmod(), blog(), bmodinv() and bmodpow() (partial)
  1665.  
  1666. =back
  1667.  
  1668. =head1 LICENSE
  1669.  
  1670. This program is free software; you may redistribute it and/or modify it under
  1671. the same terms as Perl itself.
  1672.  
  1673. =head1 SEE ALSO
  1674.  
  1675. L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
  1676. L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
  1677.  
  1678. See L<http://search.cpan.org/search?dist=bignum> for a way to use
  1679. Math::BigRat.
  1680.  
  1681. The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
  1682. may contain more documentation and examples as well as testcases.
  1683.  
  1684. =head1 AUTHORS
  1685.  
  1686. (C) by Tels L<http://bloodgate.com/> 2001 - 2005.
  1687.  
  1688. =cut
  1689.